home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_200 / 283_03 / burlap.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-12-16  |  40.8 KB  |  1,698 lines

  1.  
  2.  
  3. /* burlap.c : 11/29/88, 12/11/88, et seq., d.c.oshel */
  4.  
  5. #include "burlap.h"
  6. #include <fcntl.h>
  7.  
  8. #define COLORFILE "BURLAP.CFG"
  9.  
  10. #define ONCE 0  /* does new_record() continue looping? */
  11. #define MANY 1
  12.  
  13. char far *burlap_screen = (char far *) NULL;
  14. int delimiter = ',';
  15. char *parameter_file_name;
  16. char *screen_file_name;
  17. char *macro_file_name;
  18.  
  19. /*=============================================*/
  20. /*          Definitions of Fields Used         */
  21. /*=============================================*/
  22.  
  23. FIELDS LastName, FirstName, Company, Address1, Address2,
  24.        City, State, ZipCode, Salutation, HomePhone, WorkPhone,
  25.        Comment, NameLine, CoLine, A1Line, A2Line, CityLine;
  26.  
  27.  
  28.  
  29. /*=============================================*/
  30. /*               Field Validaters              */
  31. /*=============================================*/
  32.  
  33.  
  34. /* concatenate FirstName, LastName and place the result into NameLine
  35.    */
  36. static int concatnames( char *p, int x, int y, int len )
  37. {
  38.     char *q;
  39.     int i;
  40.  
  41.     memset( p, SPC, len );
  42.     q = strdup( FirstName );
  43.     strip_blanks(q);
  44.     for ( i = 0; *q && i < len; i++, q++, p++ )
  45.         *p = *q;
  46.     free(q);
  47.     if ( i > 0 && i < len )
  48.     {
  49.         p++;
  50.         i++;
  51.         q = strdup( LastName );
  52.         strip_blanks(q);
  53.         for ( ; *q && i < len; i++, q++, p++ )
  54.             *p = *q;
  55.         free(q);
  56.     }
  57.     return (1);
  58. }
  59.  
  60.  
  61. /* concatenate City, State, ZipCode and place the result into CityLine
  62.    */
  63. static int concattown( char *p, int x, int y, int len )
  64. {
  65.     char *q, *c, *s,*z;
  66.     int i;
  67.  
  68.     memset( p, SPC, len );
  69.  
  70.     c = strdup( City );
  71.     s = strdup( State );
  72.     z = strdup( ZipCode );
  73.  
  74.     strip_blanks(c);
  75.     strip_blanks(s);
  76.     strip_blanks(z);
  77.  
  78.     for ( i = 0, q = c; *q && i < len; i++, q++, p++ )
  79.         *p = *q;
  80.     if (strlen(c))
  81.     {
  82.         *p++ = ',';
  83.         i++;
  84.         i++;
  85.         p++;
  86.     }
  87.     for ( q = s; *q && i < len; i++, q++, p++ )
  88.         *p = *q;
  89.  
  90.     for ( i++, p++, q = z; *q && i < len; i++, q++, p++ )
  91.         *p = *q;
  92.  
  93.     free(c);
  94.     free(s);
  95.     free(z);
  96.  
  97.     return (1);
  98. }
  99.  
  100. static int moveco( char *p, int x, int y, int len )
  101. {
  102.     memcpy( p, Company, len );
  103.     return (1);
  104. }
  105. static int movea1( char *p, int x, int y, int len )
  106. {
  107.     memcpy( p, Address1, len );
  108.     return (1);
  109. }
  110. static int movea2( char *p, int x, int y, int len )
  111. {
  112.     memcpy( p, Address2, len );
  113.     return (1);
  114. }
  115.  
  116.  
  117. /*=============================================*/
  118. /*              Screen Layout                  */
  119. /*=============================================*/
  120.  
  121.  
  122. DEFINE_FIELDS( burlap )
  123. #define TOP 0
  124.  
  125.     TEXT( LastName,   21,  3, SLIDE(38) )
  126.     TEXT( FirstName,  21,  4, SLIDE(38) )
  127.     TEXT( Company,    21,  5, SLIDE(38) )
  128.     TEXT( Address1,   21,  6, SLIDE(38) )
  129.     TEXT( Address2,   21,  7, SLIDE(38) )
  130.     TEXT( City,       21,  8, SLIDE(38) )
  131.     TEXT( State,      21,  9, SLIDE(38) )
  132.     TEXT( ZipCode,    21, 10, SLIDE(38) )
  133.     TEXT( Salutation, 21, 11, SLIDE(38) )
  134.     TEXT( HomePhone,  21, 12, SLIDE(38) )
  135.     TEXT( WorkPhone,  21, 13, SLIDE(38) )
  136.     TEXT( Comment,    21, 14, SLIDE(38) )
  137.  
  138. #define NUMBER_OF_REAL_FIELDS 12
  139.  
  140.     VIRTUAL( NameLine,    8, 17, 45, concatnames )
  141.     VIRTUAL( CoLine,      8, 18, 45, moveco )
  142.     VIRTUAL( A1Line,      8, 19, 45, movea1 )
  143.     VIRTUAL( A2Line,      8, 20, 45, movea2 )
  144.     VIRTUAL( CityLine,    8, 21, 45, concattown )
  145.  
  146. #define NUMFIELDS NUMBER_OF_REAL_FIELDS+5
  147.  
  148. #define ALLOCATE NUMFIELDS
  149.  
  150. END_FIELDS
  151.  
  152. int ISAM_field_range = NUMBER_OF_REAL_FIELDS;  /* important GLOBAL */
  153.  
  154.  
  155. static char field [ BUFSIZE ];
  156. static char buffer[ BUFSIZE ];
  157.  
  158. char vrec[ BUFSIZE ];  /* current ISAM record buffer, all reads */
  159. char vout[ BUFSIZE ];  /* new ISAM record buffer, all writes */
  160. int vrec_len = 0;
  161.  
  162.  
  163.  
  164. /*
  165. =================================================================
  166.    CAUTION:  *** This is a TRICK ***
  167.  
  168.    the r2 alias defines the order in which the allocated fields
  169.    of the form should be edited; it is only referred to in calls
  170.    to _onepageform()
  171. =================================================================
  172. */
  173. DEFINE_FIELDS( r2 )
  174.     TEXT( LastName,   21,  3, SLIDE(38) )
  175.     TEXT( FirstName,  21,  4, SLIDE(38) )
  176.     VIRTUAL( NameLine,    8, 17, 45, concatnames )
  177.     TEXT( Company,    21,  5, SLIDE(38) )
  178.     VIRTUAL( CoLine,      8, 18, 45, moveco )
  179.     TEXT( Address1,   21,  6, SLIDE(38) )
  180.     VIRTUAL( A1Line,      8, 19, 45, movea1 )
  181.     TEXT( Address2,   21,  7, SLIDE(38) )
  182.     VIRTUAL( A2Line,      8, 20, 45, movea2 )
  183.     TEXT( City,       21,  8, SLIDE(38) )
  184.     TEXT( State,      21,  9, SLIDE(38) )
  185.     TEXT( ZipCode,    21, 10, SLIDE(38) )
  186.     VIRTUAL( CityLine,    8, 21, 45, concattown )
  187.     TEXT( Salutation, 21, 11, SLIDE(38) )
  188.     TEXT( HomePhone,  21, 12, SLIDE(38) )
  189.     TEXT( WorkPhone,  21, 13, SLIDE(38) )
  190.     TEXT( Comment,    21, 14, SLIDE(38) )
  191. END_FIELDS
  192.  
  193.  
  194. /* Control-C mesmerizer */
  195. static jmp_buf isis;
  196. static void osiris( void )
  197. {
  198.     longjmp(isis,-1);
  199. }
  200.  
  201.  
  202. void ISAM_crash( char *p )
  203. {
  204.     bomb("c-tree(TM) %s Error %d File %d",p,isam_err,isam_fil);
  205. }
  206.  
  207.  
  208. static char *mstop[] = {
  209.     "No!",
  210.     "Yes"
  211. };
  212.  
  213. int ask( char *msg )
  214. {
  215.     int n;
  216.     fullscreen();
  217.     gotoxy( 62,1+16 );
  218.     wputs( msg );
  219.     n = select( 63, 1+18, &mstop[0], (sizeof(mstop)/sizeof(char *)));
  220.     fullscreen();
  221.     return (n);
  222. }
  223.  
  224.  
  225. static void load_default_macro( void )
  226. {
  227.     char *p;
  228.     int i,j,c;
  229.     FILE *mfile;
  230.  
  231.     if ( macro_file_name == (char *) NULL )
  232.         return;
  233.  
  234.     strset( macro_buffer, SPC );
  235.  
  236.     if ( (mfile = fopen( macro_file_name,"rt" )) != NULL && !ferror(mfile) )
  237.     {
  238.         for ( p = ¯o_buffer[0], c = fgetc( mfile ), i = j = 0; 
  239.               c != EOF && j < 4 && i < 256;
  240.               c = fgetc( mfile), i++ )
  241.         {
  242.             if ( ferror( mfile ) )
  243.                 bomb("can't read macro file: %s", macro_file_name );
  244.  
  245.             if ( !isprint(c) )
  246.             {
  247.                 j++;
  248.                 i = j * 64;
  249.             }
  250.             else
  251.             {
  252.                 *(p + i) = c;
  253.             }
  254.         }
  255.         fclose(mfile);
  256.     }
  257. }
  258.  
  259.  
  260.  
  261. /* === strip_blanks === 
  262. ** removes leading or trailing blanks from the argument, returns nothing
  263. */
  264. void strip_blanks( char *q )
  265. {
  266.       char *p;
  267.  
  268.       for ( p = q; *p == SPC; p++ )
  269.       ;
  270.  
  271.       if (p > q) 
  272.           memcpy( q, p, strlen(p)+1 );
  273.  
  274.       if ( (p = strchr( q, EOL )) != NULL )
  275.         for ( ; p >= q && !isgraph(*p); p-- )
  276.           *p = EOL;
  277. }
  278.  
  279.  
  280.  
  281. /* === getline ===
  282. ** This has the virtue of correctly reading files which
  283. ** have characters with their high bits set (Wordstar, etc.);
  284. ** getline() will strip high bits from the characters received,
  285. ** and does NOT store control characters in the receiving buffer.
  286. **
  287. ** Reads until '\n' or end of file.
  288. **
  289. ** Will read lines longer than BUFSIZE (excess ignored)
  290. ** and correctly initializes buffer for empty input
  291. */ 
  292.  
  293. static void getline( FILE *fptr, char buffer[] )
  294. {
  295.      static int c, cnt;
  296.  
  297.      cnt = 0;
  298.      memset( buffer, 0, BUFSIZE );
  299.  
  300.      while (1)
  301.      {
  302.          buffer[ cnt ] = EOL;  /* so that if empty line, buffer is right */
  303.  
  304.          c = ((fgetc( fptr )) & 0x7F);
  305.  
  306.          if ( ferror( fptr ) )
  307.          {
  308.              bomb("read error: %s", strerror(errno));
  309.          }
  310.          else if ( feof( fptr ) )
  311.          {
  312.             return;
  313.          }
  314.          else if ( c == '\n' )
  315.          {
  316.             return;
  317.          }
  318.          else if (iscntrl(c))  /* any other control char */
  319.          {
  320.             /* do nothing, eat it */
  321.             ;
  322.          }
  323.          else if (cnt < (BUFSIZE - 1)) /* truncate, but continue reading line */
  324.          {
  325.             buffer[ cnt++ ] = c;
  326.          }
  327.      }
  328. }
  329.  
  330.  
  331. /* === nextfield ===
  332. ** Moves contents of the CURRENT delimited field from bufptr[] to field[];
  333. ** returns a pointer to the NEXT field, or to NULL if no fields remain.
  334. **
  335. ** Properly reads double- and single-quoted strings with embedded commas,
  336. ** embedded complementary single- or double-quotes, and embedded
  337. ** double-double- or double-single-quotation marks.  This means, that
  338. ** nextfield can tweeze field information out of comma-delimited text
  339. ** records created by or for WordStar, MailMerge, PC-Write, dBase II or ///,
  340. ** R:Base 5000, or BASIC.  And, no doubt, &c.
  341. */
  342.  
  343. static char * nextfield( char * bufptr )
  344. {
  345.       int match, matchtest;
  346.       char *fldptr;
  347.  
  348.       memset( field, 0, BUFSIZE );
  349.       if ( bufptr == NULL )
  350.           return ( NULL );
  351.  
  352.       fldptr = field;
  353.       match = EOL;
  354.  
  355.       while (1)
  356.       {
  357.            *fldptr = EOL;
  358.  
  359.            if ( *bufptr == EOL )
  360.            {
  361.                 break;
  362.            }
  363.            else if ( *bufptr == match )
  364.            {
  365.                 bufptr++;
  366.                 /* BASIC's double-quote, e.g., "Billy ""Bob"" Smith" */ 
  367.                 if ( *bufptr == match )
  368.                 {
  369.                     *fldptr = *bufptr;
  370.                     bufptr++;
  371.                     fldptr++;
  372.                 }
  373.                 else match = EOL;
  374.            }
  375.            else if ( *bufptr == QUOTE || *bufptr == APOSTROPHE )
  376.            {
  377.                 matchtest = (*bufptr == QUOTE)? APOSTROPHE : QUOTE;
  378.  
  379.                 if ( match == matchtest )
  380.                 {
  381.                      *fldptr = *bufptr;
  382.                      bufptr++;
  383.                      fldptr++;
  384.                 }
  385.                 else /* match is EOL, QUOTE was in previous test */
  386.                 {
  387.                      if ( fldptr == field )
  388.                      {
  389.                           match = *bufptr; 
  390.                           bufptr++;
  391.                      }
  392.                      else
  393.                      {
  394.                           *fldptr = *bufptr;
  395.                           bufptr++;
  396.                           fldptr++;
  397.                      }
  398.                 }
  399.            }
  400.            else if ( *bufptr == delimiter && match == EOL )
  401.            {
  402.                 bufptr++;
  403.                 break;
  404.            }
  405.            else
  406.            {
  407.                 *fldptr = *bufptr;
  408.                 bufptr++;
  409.                 fldptr++;
  410.            }
  411.       }
  412.       *fldptr = EOL;  /* just in case */
  413.  
  414.       return ( (*bufptr == EOL) ? NULL : bufptr );
  415. }
  416.  
  417.  
  418.  
  419.  
  420. /* enter with data in the FORM_RULES array
  421. ** write variable length ISAM record
  422. */
  423. static void add_var_record( void )
  424. {
  425.     int i,j;
  426.     char *q;
  427.  
  428.     memset( vout, 0, BUFSIZE );
  429.     vrec_len = 0;
  430.  
  431.     for ( i = 0; i < ISAM_field_range; i++ )
  432.     {
  433.         q = strdup( *(burlap[i].fptr) );
  434.         strip_blanks( q );
  435.         for ( j = 0; *(q+j) != EOL; j++ )
  436.         {
  437.             vout[ vrec_len ] = *(q+j);
  438.             if ( vrec_len < BUFSIZE )
  439.                 vrec_len++;
  440.         }
  441.         vout[ vrec_len ] = EOL;
  442.         if ( vrec_len < BUFSIZE )
  443.             vrec_len++;
  444.         free( q );
  445.     }
  446.     if ( vrec_len > 0 )
  447.         if ( ADDVREC( datno, vout, vrec_len ) )
  448.             ISAM_crash("ADDVREC");
  449. }
  450.  
  451.  
  452. static void screenmessage( char *p, int x, int y, int len )
  453. {
  454.     MSJ_SetFldAttr( SPC, tm+y, lm+x, vid_attr, len, &video );
  455.     MSJ_DispMsgLen(   p, tm+y, lm+x, len, &video );
  456. }
  457.  
  458. /* convert record from ascii file to a variable length ISAM record
  459. */
  460. static void process_record( void )
  461. {
  462.     char **f;
  463.     char *p, *q;
  464.     int i,m,n,x,y,len;
  465.     VALIDATER fi;
  466.  
  467.     p = buffer;
  468.     i = 0;
  469.     do
  470.     {
  471.         f = burlap[i].fptr;
  472.         x = burlap[i].x;
  473.         y = burlap[i].y;
  474.         len = abs( burlap[i].len );
  475.  
  476.         /* erase field in form */
  477.         q = *f;
  478.         memset( q, SPC, MAXVFLDLEN );
  479.         *(q+MAXVFLDLEN) = EOL;
  480.  
  481.         /* current field in the input buffer is moved to the field array
  482.            as a side effect of this call,
  483.            then p advances to the next field in the input buffer;
  484.            if p is NULL, there is no more data (perhaps unexpectedly?)
  485.            */
  486.         if ( p == NULL )
  487.             *field = EOL;
  488.         else
  489.             p = nextfield( p );
  490.  
  491.         strip_blanks( field );
  492.  
  493.         /* move field to field in form */
  494.         memcpy( q, field, min( strlen(field), MAXVFLDLEN ) );
  495.  
  496.         screenmessage( q,x,y,len );
  497.  
  498.         i++;
  499.     }
  500.     while ( i < ISAM_field_range );
  501.  
  502.     for ( i = ISAM_field_range; i < NUMFIELDS; i++ )
  503.     {
  504.         f = burlap[i].fptr;
  505.         x = burlap[i].x;
  506.         y = burlap[i].y;
  507.         len = abs( burlap[i].len );
  508.         fi = burlap[i].fi;
  509.  
  510.         q = *f;
  511.  
  512.         if ( fi != VNOP )
  513.             (*fi)(q,x,y,len);
  514.  
  515.         screenmessage( q,x,y,len );
  516.     }
  517.  
  518.     add_var_record();
  519. }
  520.  
  521.  
  522.  
  523. void put_screen( void )
  524. {
  525.     static char *info[] = {
  526.         "^1Burlap is free!  Give it away!^0",
  527.         "by",
  528.         "David C. Oshel",
  529.         "1219 Harding Avenue",
  530.         "Ames, Iowa 50010",
  531.         "",
  532.         "^1ISAM file management by FairCom's c-tree(TM)^0",
  533.         "Portions of the compiled version of this",
  534.         "program are the property of FairCom, Inc.,",
  535.         "4006 W. Broadway, Columbia, MO 65203.",
  536.         NULL
  537.     };
  538.     static int flag = 1;
  539.     char **p;
  540.     int y;
  541.     if ( flag )
  542.     {
  543.         fullscreen();
  544.         hidecursor();
  545.         clrscrn();
  546.         windowbox( 5,5,75,18 );
  547.         fullscreen();
  548.         for ( y = 7, p = info; *p != NULL; p++, y++ )
  549.         {
  550.             gotoxy( (((80-strlen(*p))/2)+(strchr(*p,'^')==NULL?0:2)),y );
  551.             wputs( *p );
  552.         }
  553.         burlap_screen = PrepScreen( screen_file_name );
  554.         sleep(100);
  555.         defcursor();
  556.         flag = 0;
  557.     }
  558.     PopScreen( burlap_screen );
  559. }
  560.  
  561.  
  562. static int ISAM_open = 0;
  563.  
  564. static void reopen_ISAM_files( void )
  565. {
  566.     int i;
  567.     while ( i = OPNISAM( parameter_file_name ) )
  568.     {
  569.         if ( i == 12 )
  570.         {
  571.             if ( CREISAM( parameter_file_name ) )
  572.                 bomb("c-tree(TM) CREISAM \"%s\" Error %d File %d", parameter_file_name, isam_err, isam_fil );
  573.             if ( CLISAM() )
  574.                 bomb("c-tree(TM) CLISAM Error %d File %d", isam_err, isam_fil );
  575.         }
  576.         else
  577.         {
  578.             bomb("c-tree(TM) OPNISAM \"%s\" Error %d File %d", parameter_file_name, isam_err, isam_fil );
  579.         }
  580.     }
  581.     ISAM_open = 1;
  582. }
  583.  
  584.  
  585.  
  586. static void close_ISAM_files( void )
  587. {
  588.     if ( ISAM_open && CLISAM() )
  589.         bomb("c-tree(TM) CLISAM Error %d File %d", isam_err, isam_fil );
  590.     ISAM_open = 0;
  591. }
  592.  
  593.  
  594.  
  595.  
  596.  
  597.  
  598.  
  599. /*============= Dump to ASCII File ========================*/
  600.  
  601. static char *bufptr;
  602.  
  603. static void verbatimfield( char *p )
  604. {
  605.      for ( ; *p; bufptr++, p++ )
  606.      {
  607.           *bufptr = *p;
  608.      }
  609. }
  610.  
  611.  
  612.  
  613. static void quotefield( char *p )
  614. {
  615.      static int fieldquotemark;
  616.  
  617.      fieldquotemark = ((strchr(p,QUOTE) == NULL) ? QUOTE : APOSTROPHE);
  618.      *bufptr++ = fieldquotemark;
  619.      for ( ; *p; bufptr++, p++ )
  620.      {
  621.           if (*p == fieldquotemark)
  622.           {
  623.               *bufptr++ = *p; /* double-double quote */
  624.           }
  625.           *bufptr = *p;
  626.      }
  627.      *bufptr++ = fieldquotemark;
  628. }
  629.  
  630.  
  631.  
  632.  
  633. static int concatenate_fields( void ) 
  634. {
  635.      static int cnt, goodfields;
  636.  
  637.      bufptr = buffer;
  638.      goodfields = 0; 
  639.      for ( cnt = 0; cnt < ISAM_field_range; cnt++ )
  640.      {
  641.           strcpy( field, *(burlap[ cnt ].fptr) );
  642.  
  643.           strip_blanks( field );
  644.           goodfields |= strlen( field );
  645.           if ( strchr( field, delimiter ) == NULL )  /* there is NO comma */
  646.           {
  647.               if ( field[0] != QUOTE && field[0] != APOSTROPHE )
  648.               {
  649.                    verbatimfield( field ); /* NO spurious quote */
  650.               }
  651.               else quotefield( field );
  652.           }
  653.           /* case of "has-comma && has-spurious-quote" reduces to the
  654.           ** same case as merely one or the other, the way we do things
  655.           *------------------------------------------
  656.           else if ( *field != QUOTE && *field != APOSTROPHE )  
  657.           {
  658.                quotefield( field );
  659.           }
  660.           -------------------------------------------
  661.           */
  662.           else quotefield( field );  /* there IS a comma in the field! */
  663.  
  664.           *bufptr++ = delimiter;
  665.      }
  666.  
  667.      if (bufptr > buffer) --bufptr;  /* point at spurious final delimiter */
  668.      *bufptr = EOL;
  669.  
  670.      return ( goodfields );  /* were there any fields in the user input? */
  671. }
  672.  
  673.  
  674.  
  675. static void dump_ascii_file( void )
  676. {
  677.     static char *indexes[] = {
  678.         "Name order",
  679.         "Zipcode order",
  680.         "Company order",
  681.         "Return"
  682.     };
  683.     FILE *f;
  684.     int n, index, cnt;
  685.     char numbuf[8];
  686.     union REGS crs;
  687.  
  688.  
  689.     nboxmsg( "Export delimited file %s", ASCIIFILE );
  690.     blopbloop();
  691.  
  692.     if ( !ask( "^1Export file?^0" ) )
  693.         return;
  694.  
  695.     if ( (index = 1 + select( MLOC, 1, &indexes[0], (sizeof(indexes)/sizeof(char *)) )) > 3 )
  696.         return;
  697.  
  698.     select_flag = SKIP_FORM;
  699.     if ( ask( "Select records?" ) )
  700.         if ( !choose_records() )
  701.             return;
  702.  
  703.     fullscreen();
  704.     put_screen();
  705.     hidecursor();
  706.     gotoxy( 62,2 );
  707.     wputs( "^1Esc^0 halts!" );
  708.     windowbox( 0,6,79,24 );
  709.     fullscreen();
  710.     gotoxy( 2,5 );
  711.     wprintf( "╡^2 Exporting in %s -> %s ^0╞", indexes[index-1], ASCIIFILE );
  712.     setwindow( 1,6,78,23 );
  713.     gotoxy(0,0);
  714.  
  715.  
  716.     f = fopen( ASCIIFILE, "wt" );
  717.     if ( f == NULL || ferror(f) )
  718.         bomb("Could not open %s", ASCIIFILE );
  719.  
  720.  
  721.     for ( cnt = 0,n = FRSREC(index,vrec); n != 101; n = NXTREC(index,vrec) )
  722.     {
  723.         if ( n )
  724.             ISAM_crash("NXTREC");
  725.  
  726.         if ( REDVREC( datno,vrec,BUFSIZE ) )
  727.             ISAM_crash("REDVREC");
  728.  
  729.         sprintf( numbuf, "%d", ++cnt );
  730.         savecursor( &crs );
  731.         fullscreen();
  732.         screenmessage( numbuf,62,5,strlen(numbuf) );
  733.         setwindow( 1,6,78,23 );
  734.         restcursor( &crs );
  735.  
  736.         load_form();
  737.  
  738.         if ( kbhit() )  /* stop and go on keypress */
  739.         {
  740.             while ( kbhit() )
  741.                 if ( getch() == ESC )
  742.                     goto zoo;
  743.             while ( !kbhit() )
  744.                 ;
  745.             while ( kbhit() )
  746.                 if ( getch() == ESC )
  747.                     goto zoo;
  748.         }
  749.  
  750.         if ( selected() && concatenate_fields() )
  751.         {
  752.             wprintf( "%s\n", buffer );
  753.             fprintf( f, "%s\n", buffer );
  754.             if ( ferror(f) )
  755.                 bomb( "Could not write %s", ASCIIFILE );
  756.         }
  757.     }
  758.     zoo:
  759.     while ( kbhit() ) getch();
  760.  
  761.     fullscreen();
  762.     defcursor();
  763.  
  764.     fclose( f );
  765.     if ( ferror( f ) )
  766.         bomb( "Could not close %s", ASCIIFILE );
  767.  
  768.  
  769.     /* make last record the current ISAM record on exit */
  770.     if ( LSTREC(index,vrec) )
  771.         ;
  772. }
  773.  
  774.  
  775. /*=================== Load ASCII File ======================*/
  776.  
  777. static void load_ascii_file( void )
  778. {
  779.  
  780.     FILE *f;
  781.  
  782.     nboxmsg( "Import delimited file %s", ASCIIFILE );
  783.     bopbleet();
  784.  
  785.     if ( !ask( "^1Import file?^0" ) )
  786.         return;
  787.  
  788.     if ( access( ASCIIFILE, 0 ) != 0 )
  789.     {
  790.         boxmsg( "%s not found, data not loaded!", ASCIIFILE );
  791.         return;
  792.     }
  793.  
  794.     /*========== DESTRUCTIVE Method =============
  795.     nboxmsg( "Removing old files..." );
  796.  
  797.     close_ISAM_files();
  798.  
  799.     remove( ISAMFILE );
  800.     remove( INDXFILE );
  801.  
  802.     reopen_ISAM_files();
  803.     ===========================================*/
  804.  
  805.     if ( (f = fopen( ASCIIFILE, "rt" )) == NULL || ferror(f) )
  806.     {
  807.         boxmsg( "Source file error: %s", strerror(errno) );
  808.         return;
  809.     }
  810.  
  811.     fullscreen();
  812.     put_screen();
  813.     gotoxy( 2,0 );
  814.     wprintf( "╡^2 Importing <- %s ^0╞", ASCIIFILE );
  815.     gotoxy( 62,18 );
  816.     wputs( "^1Esc^0 halts!" );
  817.     intense_video();
  818.     while ( kbhit() ) getch();
  819.  
  820.     do
  821.     {
  822.         getline( f, buffer );
  823.         if ( *buffer )
  824.         {
  825.             process_record();
  826.         }
  827.         if ( kbhit() && getch() == ESC )
  828.         {
  829.             boxmsg( "** OK, stopping with a partial load! **" );
  830.             break;
  831.         }
  832.     }
  833.     while ( !feof(f) );
  834.  
  835.     fclose (f);
  836.  
  837.     close_ISAM_files();
  838.     reopen_ISAM_files();
  839. }
  840.  
  841.  
  842. static void add_message( void )
  843. {
  844.     static char *msg[] = {
  845.         "^2Add record^0",
  846.         "^1F10^0 assists",
  847.         "^1Esc^0 when done",
  848.         NULL
  849.     };
  850.     char **p;
  851.     int n;
  852.  
  853.     for ( n = 0, p = msg; *p != NULL; n++, p++ )
  854.     {
  855.         gotoxy( 63,18+n );
  856.         wputs( *p );
  857.     }
  858. }
  859.  
  860.  
  861.  
  862. static void edit_message( void )
  863. {
  864.     static char *msg[] = {
  865.         "^2Edit record^0",
  866.         "^1F10^0 assists",
  867.         "^1Esc^0 when done",
  868.         NULL
  869.     };
  870.     char **p;
  871.     int n;
  872.  
  873.     for ( n = 0, p = msg; *p != NULL; n++, p++ )
  874.     {
  875.         gotoxy( 63,18+n );
  876.         wputs( *p );
  877.     }
  878. }
  879.  
  880.  
  881.  
  882. static void new_record( int many )
  883. {
  884.     int i, len, more;
  885.  
  886.     do
  887.     {
  888.         more = 0;
  889.         fullscreen();
  890.         put_screen();
  891.         add_message();
  892.         for ( i = 0; i < NUMFIELDS; i++ )
  893.         {
  894.             len = (burlap[i].len < 0) ? MAXVFLDLEN : burlap[i].len;
  895.             memset( *(burlap[i].fptr), SPC, len );
  896.         }
  897.         if ( _onepageform( NULL, r2, NUMFIELDS ) == SAVE_FORM )
  898.         {
  899.             add_var_record();
  900.             more = many;  /* i.e., ONCE or MANY, depending who calls */
  901.         }
  902.     }
  903.     while ( more );
  904. }
  905.  
  906.  
  907.  
  908. void load_form( void )
  909. {
  910.     int i,len;
  911.     char *p;
  912.  
  913.     for ( p = vrec, i = 0; i < ISAM_field_range; i++ )
  914.     {
  915.         len = (burlap[i].len < 0) ? MAXVFLDLEN : burlap[i].len;
  916.  
  917.         memset( *(burlap[i].fptr), SPC, len );
  918.         memcpy( *(burlap[i].fptr), p, strlen(p) );
  919.         p = strchr( p, '\0' );
  920.         p++;
  921.     }
  922. }
  923.  
  924.  
  925.  
  926. void show_form( void )
  927. {
  928.     /*--------- this function is in Fafnir (!) ------------
  929.         DisplayForm( burlap_screen, burlap, NUMFIELDS );
  930.  
  931.         It is not used, however, to keep PopScreen from 
  932.         erasing current info on the active screen.
  933.     -----------------------------------------------------*/
  934.     char *p;
  935.     int i,x,y,len;
  936.     VALIDATER fi;
  937.  
  938.     fullscreen();
  939.     intense_video();
  940.     hidecursor();
  941.     for ( i = 0; i < NUMFIELDS; i++ )
  942.     {
  943.         p   = *(burlap[i].fptr);
  944.         x   = burlap[i].x;
  945.         y   = burlap[i].y;
  946.         len = abs( burlap[i].len );
  947.         fi  = burlap[i].fi;
  948.         if ( fi != VNOP )
  949.             (*fi) (p,x,y,len);  /* all with initializers are NOT sliding! */
  950.         screenmessage( p,x,y,len );
  951.     }
  952.     normal_video();
  953.     defcursor();
  954. }
  955.  
  956.  
  957.  
  958. static void delete_record( void )
  959. {
  960.     if ( DELVREC( datno ) )
  961.         ISAM_crash("DELVREC");
  962. }
  963.  
  964.  
  965.  
  966. static int delete_dialogue( void )
  967. {
  968.     if ( ask( "^1Delete Record?^0" ) )
  969.     {
  970.         put_screen();     /* wipe from screen */
  971.         delete_record();
  972.         return (1);
  973.     }
  974.     return (0);
  975. }
  976.  
  977.  
  978.  
  979. /*======== label printing routines ========*/
  980.  
  981. static void dl0( FILE *label )  /* FILE is open, may be stdprn */
  982. {
  983.     int i, l;
  984.     char *q;
  985.  
  986.     /* write "smart" label, i.e., all blank lines are at the
  987.        bottom of the label; assumes labels are 6 lines/inch
  988.        */
  989.     for ( l = 0, i = ISAM_field_range; i < NUMFIELDS; i++ )
  990.     {
  991.         q = strdup( *(burlap[i].fptr) );
  992.         strip_blanks(q);
  993.         if ( strlen(q) )
  994.         {
  995.             /* echo line to reverse-video label area on screen */
  996.             wputs( q );
  997.             if ( ++l < 5 )
  998.                 wink('\n');
  999.  
  1000.             /* now print, in case label==printer and it's offline */
  1001.             fprintf( label, "%s\r\n", q );
  1002.             if ( ferror(label) )
  1003.                 bomb("Can't write $ file: %s", strerror(errno) );
  1004.  
  1005.         }
  1006.         free (q);
  1007.     }
  1008.  
  1009.     /* fill in remainder of 6-line label with blank lines in $ file */
  1010.     for ( ; l < 6; l++ )
  1011.     {
  1012.         fprintf( label, "\r\n" );
  1013.         if ( ferror(label) )
  1014.             bomb("Can't write $ file: %s", strerror(errno) );
  1015.     }
  1016. }
  1017.  
  1018.  
  1019.  
  1020. static void label_dialogue( void )
  1021. {
  1022.     static char *style[] = {
  1023.         "Write over $",
  1024.         "Append to $",
  1025.         "Print label",
  1026.         "Return"
  1027.     };
  1028.  
  1029.     int n;
  1030.     FILE *label;
  1031.  
  1032.     fullscreen();
  1033.     gotoxy( 62,1+16 );
  1034.     wputs( "^1Address label^0" );
  1035.     if ( (n = select( 63,1+18,&style[0],(sizeof(style)/sizeof(char *)))) > 2 )
  1036.         return;
  1037.  
  1038.     setwindow( 7,17,53,21 );
  1039.     reverse_video();
  1040.     clrwindow();
  1041.     gotoxy(0,0);
  1042.  
  1043.     if ( n < 2 )
  1044.     {
  1045.         label = fopen( "$", (n == 0 ? "wb" : "ab") );
  1046.         if ( label == NULL || ferror(label) )
  1047.             bomb("Can't open $ file: %s", strerror(errno) );
  1048.         dl0( label );
  1049.         fclose( label );
  1050.         if ( ferror(label) )
  1051.             bomb("Can't close $ file: %s", strerror(errno) );
  1052.     }
  1053.     else
  1054.     {
  1055.         nboxmsg( "** Printer **" );
  1056.         dl0( stdprn );
  1057.         fflush( stdprn );
  1058.     }
  1059.  
  1060.     normal_video();
  1061.     fullscreen();
  1062. }
  1063.  
  1064.  
  1065.  
  1066.  
  1067. static int counter = 0;
  1068. static int find_string( COUNT index, char *locate, int direction )
  1069. {
  1070.     int i, n;
  1071.     char *p;
  1072.  
  1073.     strupr( locate );
  1074.  
  1075.     while (1)
  1076.     {
  1077.         if ( kbhit() )
  1078.         {
  1079.             if ( getch() == ESC )
  1080.             {
  1081.                 return (0);  /* user interrupts search */
  1082.             }
  1083.         }
  1084.  
  1085.         if ( direction == 0 )
  1086.         {
  1087.             nboxmsg( "%d", counter++ );
  1088.             if ( (n = NXTREC( index, vrec )) == 101 )
  1089.             {
  1090.                 /* we're at end of file */
  1091.                 if ( LSTREC( index, vrec ) != 0 )
  1092.                 {
  1093.                     ISAM_crash("LSTREC");
  1094.                 }
  1095.                 boxmsg( "End of file" );
  1096.                 break;
  1097.             }
  1098.             else if ( n != 0 )
  1099.                 ISAM_crash("NXTREC");
  1100.         }
  1101.         else
  1102.         {
  1103.             nboxmsg( "%d", counter-- );
  1104.             if ( (n = PRVREC( index, vrec )) == 101 )
  1105.             {
  1106.                 /* we're at beginning of file */
  1107.                 if ( FRSREC( index, vrec ) != 0 )
  1108.                 {
  1109.                     ISAM_crash("FRSREC");
  1110.                 }
  1111.                 boxmsg( "Beginning of file" );
  1112.                 break;
  1113.             }
  1114.             else if ( n != 0 )
  1115.                 ISAM_crash("PRVREC");
  1116.         }
  1117.  
  1118.         if ( REDVREC( datno, vrec, BUFSIZE ) )  /* read the record */
  1119.         {
  1120.             ISAM_crash("REDVREC");
  1121.         }
  1122.  
  1123.         if ( load_form(), selected() )
  1124.             return (1);
  1125.  
  1126.         /*----- old way -------
  1127.         for ( p = vrec, i = 0; i < ISAM_field_range; p++, i++ )
  1128.         {
  1129.             if ( strstr( strupr(p), locate ) )
  1130.             {
  1131.                 return (1);
  1132.             }
  1133.             p = strchr(p,'\0');
  1134.         }
  1135.         -----------------------*/
  1136.     }
  1137.     return (0); /* no match in any record from point of search */
  1138. }
  1139.  
  1140.  
  1141.  
  1142. static void locate_record( COUNT index, char *p )
  1143. {
  1144.     static char *loc[] = {
  1145.         "Locate next",
  1146.         "Locate previous",
  1147.         "Edit record",
  1148.         "Return"
  1149.     };
  1150.     int n, direction;
  1151.  
  1152.     fullscreen();
  1153.     put_screen();
  1154.  
  1155.     counter = direction = 0;  /* 0=Forward, 1=Backward */
  1156.  
  1157.     while (1)
  1158.     {
  1159.         if ( !find_string(index, p, direction) )
  1160.             return;
  1161.  
  1162.         kukamonga:  /* jump up here after editing & saving a record */
  1163.  
  1164.         /* reread current record because fields were strupr'd above */
  1165.         if ( REDVREC( datno, vrec, BUFSIZE ) )  
  1166.         {
  1167.             ISAM_crash("REDVREC");
  1168.         }
  1169.  
  1170.         fullscreen();
  1171.         put_screen();
  1172.         load_form();
  1173.         show_form();
  1174.  
  1175.         switch ( select( MLOC, 1, &loc[0], (sizeof(loc)/sizeof(char *))))
  1176.         {
  1177.         case 0:  /* forward */
  1178.             direction = 0;
  1179.             break;
  1180.         case 1:  /* backward */
  1181.             direction = 1;
  1182.             break;
  1183.         case 2:  /* edit */
  1184.             fullscreen();
  1185.             put_screen();
  1186.             edit_message();
  1187.             if ( _onepageform( NULL, r2, NUMFIELDS ) == SAVE_FORM )
  1188.             {
  1189.                 nboxmsg("Updating");
  1190.                 delete_record();  /* old copy is in vrec */
  1191.                 add_var_record(); /* new copy is in form, goes to vout */
  1192.                 goto kukamonga;
  1193.             }
  1194.             break;
  1195.         default:
  1196.             return;
  1197.         }
  1198.     }    
  1199. }
  1200.  
  1201.  
  1202.  
  1203. static char *indices[] = {
  1204.     "Select Name",
  1205.     "Select Zipcode",
  1206.     "Select Company ",
  1207.     "Return"
  1208. };
  1209.  
  1210. static void scan_records( void )
  1211. {
  1212.  
  1213.     static char *directions[] = {
  1214.     /*   ....v....1....v */
  1215.         "Next record",
  1216.         "Previous record",
  1217.         "Find key",
  1218.         "Get first",
  1219.         "Get last",
  1220.         "Locate string",
  1221.         "Edit record",
  1222.         "Delete record",
  1223.         "Insert record",
  1224.         "Use other index",
  1225.         "Address label",
  1226.         "Return"
  1227.     };
  1228.  
  1229.  
  1230.     int n, index;
  1231.     static char key[] = "....v....1....v....2";  /* 20 chars  */
  1232.     static char bln[] = "                    ";  /* 20 spaces */
  1233.  
  1234.     restart:
  1235.     fullscreen();
  1236.     put_screen();
  1237.     if ( (index = 1 + select( MLOC, 1, &indices[0], (sizeof(indices)/sizeof(char *)) )) > 3 )
  1238.         return;
  1239.  
  1240.     top:
  1241.     if ( FRSREC( index, vrec ) != 0 )  /* search */
  1242.     {
  1243.         boxmsg("c-tree(TM) FRSREC Error %d File %d", isam_err,isam_fil);
  1244.         return;
  1245.     }
  1246.  
  1247.     while (1)
  1248.     {
  1249.         if ( REDVREC( datno, vrec, BUFSIZE ) )  /* read current record */
  1250.         {
  1251.             ISAM_crash("REDVREC");
  1252.         }
  1253.  
  1254.         fullscreen();
  1255.         put_screen();
  1256.         load_form();
  1257.         show_form();
  1258.  
  1259.         switch( select( MLOC, 1, &directions[0], (sizeof(directions)/sizeof(char *))))
  1260.         {
  1261.         case 0:  /* Next */
  1262.             if ( (n = NXTREC( index, vrec )) == 101 )
  1263.             {
  1264.                 /* at end of file, wrap to beginning of file */
  1265.                 if ( FRSREC( index, vrec ) != 0 )
  1266.                 {
  1267.                     ISAM_crash("FRSREC");
  1268.                 }
  1269.             }
  1270.             else if ( n != 0 )
  1271.                 ISAM_crash("NXTREC");
  1272.             break;
  1273.  
  1274.         case 1:  /* Previous */
  1275.             if ( (n = PRVREC( index, vrec )) == 101 )
  1276.             {
  1277.                 /* at beginning of file, wrap to end of file */
  1278.                 if ( LSTREC( index, vrec ) != 0 )
  1279.                 {
  1280.                     ISAM_crash("LSTREC");
  1281.                 }
  1282.             }
  1283.             else if ( n != 0 )
  1284.                 ISAM_crash("PRVREC");
  1285.             break;
  1286.  
  1287.         case 2:  /* Find */
  1288.             strcpy( key, bln ); 
  1289.             nboxmsg( "Enter key:                     " );
  1290.             fullscreen();
  1291.             EditField( key, 33, 10, (index == ixcmp? 16 : 20), 0, c2upr, VNOP );
  1292.             put_screen();
  1293.  
  1294.             if ( strcmp( key, bln ) != 0 )
  1295.             {
  1296.                 strip_blanks(key);  /* TRICK!!!  Pads key right with nulls! */
  1297.                 if ( GTEREC( index, key, vrec ) != 0 )
  1298.                 {
  1299.                     nboxmsg("%s: %s not found", indices[index-1], key);
  1300.                     goto restart;
  1301.                 }
  1302.             }
  1303.             break;
  1304.  
  1305.         case 3:  /* First Record */
  1306.             goto top;
  1307.             break;
  1308.  
  1309.         case 4:  /* Last Record */
  1310.             if ( LSTREC( index, vrec ) != 0 )  /* search */
  1311.             {
  1312.                 boxmsg("c-tree(TM) LSTREC Error %d File %d", isam_err,isam_fil);
  1313.                 return;
  1314.             }
  1315.             break;
  1316.  
  1317.         case 5:  /* Locate String */
  1318.             select_flag = SKIP_FORM;
  1319.             if ( choose_records() )
  1320.             {
  1321.                 locate_record( index, key ); /* key is a dummy, now */ 
  1322.             }
  1323.             break;
  1324.  
  1325.         case 6:  /* Edit */
  1326.             fullscreen();
  1327.             put_screen();
  1328.             edit_message();
  1329.             if ( _onepageform( NULL, r2, NUMFIELDS ) == SAVE_FORM )
  1330.             {
  1331.                 nboxmsg("Updating");
  1332.                 delete_record();  /* old copy is in vrec */
  1333.                 add_var_record(); /* new copy is in form, goes to vout */
  1334.             }
  1335.             break;
  1336.  
  1337.         case 7:  /* Delete */
  1338.             if ( delete_dialogue() )
  1339.             {
  1340.                 /* record was deleted, so advance to next record */
  1341.                 if ( (n = NXTREC( index, vrec )) == 101 )
  1342.                 {
  1343.                     /* at end of file, wrap to beginning of file */
  1344.                     if ( (n = FRSREC( index, vrec )) != 0 )
  1345.                     {
  1346.                         if ( n == 101 )
  1347.                         {
  1348.                             boxmsg("All records deleted!");
  1349.                         }
  1350.                         else
  1351.                         {
  1352.                             /* fatal error of some kind */
  1353.                             ISAM_crash("FRSREC");
  1354.                         }
  1355.                         return;
  1356.                     }
  1357.                 }
  1358.                 else if ( n != 0 )
  1359.                     ISAM_crash("NXTREC");
  1360.             }
  1361.             break;
  1362.  
  1363.         case 8:
  1364.             new_record( ONCE );  /* add just one record, on the fly */
  1365.             break;
  1366.  
  1367.         case 9:  /* other index */
  1368.             goto restart;
  1369.             break;
  1370.  
  1371.         case 10:  /* address label */
  1372.             label_dialogue();
  1373.             break;
  1374.  
  1375.         default:
  1376.             return;
  1377.             break;
  1378.         }
  1379.     }
  1380. }
  1381.  
  1382.  
  1383. static void kill_files( void )
  1384. {
  1385.     /* there must be some way to retrieve the actual pathname from
  1386.        the internal data structure which c-tree maintains (?)
  1387.        */
  1388.     if ( access( ISAMFILE,0 ) != 0 )
  1389.     {
  1390.         boxmsg( "Run KILL ISAM only in your actual BURLAP subdirectory!" );
  1391.         return;
  1392.     }
  1393.  
  1394.     nboxmsg( "Danger:  Kill ISAM ** D E S T R O Y S ** existing files!" );
  1395.  
  1396.     if ( ask( "Kill ISAM?" ) )
  1397.     {
  1398.         bopbleet();
  1399.         if ( ask( "Are you SURE?" ) )
  1400.         {
  1401.             put_screen();
  1402.             nboxmsg( "Initializing new, empty ISAM files!" );
  1403.             close_ISAM_files();
  1404.             remove( ISAMFILE );
  1405.             remove( INDXFILE );
  1406.             reopen_ISAM_files();
  1407.         }
  1408.     }
  1409. }
  1410.  
  1411. static void utilities( void )
  1412. {
  1413.     static char *utils[] = {
  1414.     /*   ....v....1....v */
  1415.         "Print labels",
  1416.         "Import ASCII",
  1417.         "Export ASCII",
  1418.         "Kill ISAM files",
  1419.         "Return"
  1420.     };
  1421.     int index;
  1422.  
  1423.     while (1)
  1424.     {
  1425.         fullscreen();
  1426.         put_screen();
  1427.         /* re-read current record, if possible */
  1428.         if ( REDVREC( datno, vrec, BUFSIZE ) == 0 ) 
  1429.         {
  1430.             load_form();
  1431.             show_form();
  1432.         }
  1433.  
  1434.         switch ( select( MLOC, 1, &utils[0], (sizeof(utils)/sizeof(char *))))
  1435.         {
  1436.         case 0:  /* print */
  1437.             fullscreen();
  1438.             put_screen();
  1439.             gotoxy( 2,0 );
  1440.             wputs( "╡^2 Print Labels ^0╞" );
  1441.             load_default_macro();
  1442.             print_labels( ixzip );
  1443.             break;
  1444.         case 1:  /* import ASCII */
  1445.             load_ascii_file();
  1446.             break;
  1447.         case 2:  /* export ASCII */
  1448.             dump_ascii_file();
  1449.             break;
  1450.         case 3:  /* delete ISAM files */
  1451.             kill_files();
  1452.             break;
  1453.         default:
  1454.             return;
  1455.             break;
  1456.         }
  1457.     }
  1458. }
  1459.  
  1460.  
  1461. /* =======  SCREEN COLOR ROUTINES ======= */
  1462.  
  1463. static char cmask[] = "%d\n";
  1464.  
  1465. static void save_color( void )
  1466. {
  1467.     FILE *cf;
  1468.  
  1469.     if ( (cf = fopen( COLORFILE, "w" )) != NULL )
  1470.     {
  1471.         fprintf( cf, cmask, vid[0] );
  1472.         fprintf( cf, cmask, vid[1] );
  1473.         fprintf( cf, cmask, vid[2] );
  1474.         fprintf( cf, cmask, vid[3] );
  1475.         fprintf( cf, cmask, video.SnowFlag );
  1476.     }
  1477.     fclose (cf);
  1478. }
  1479.  
  1480. static void get_color( void )
  1481. {
  1482.     FILE *cf;
  1483.     unsigned char a,b,c,d,e;
  1484.  
  1485.     a = vid[0];
  1486.     b = vid[1];
  1487.     c = vid[2];
  1488.     d = vid[3];
  1489.     e = video.SnowFlag;
  1490.     if ( (cf = fopen( COLORFILE, "r" )) != NULL )
  1491.     {
  1492.         fscanf( cf, cmask, &a );
  1493.         fscanf( cf, cmask, &b );
  1494.         fscanf( cf, cmask, &c );
  1495.         fscanf( cf, cmask, &d );
  1496.         fscanf( cf, cmask, &e );
  1497.         vid[0] = a;
  1498.         vid[1] = b;
  1499.         vid[2] = c;
  1500.         vid[3] = d;
  1501.         if ( video.mode != 7 )
  1502.             video.SnowFlag = e;
  1503.     }
  1504.     fclose (cf);
  1505. }
  1506.                /*   ....v....1....v */
  1507. static char pq[] = "Turn snow OFF";
  1508. static char qp[] = "Fast video ON";
  1509. static char ma[] = "Monochrome, n/a";
  1510. static char hue[] = "Video colors";
  1511. static char hil[] = "Video hilites";
  1512.  
  1513. static char *amenu[] = {
  1514.     "View/edit",
  1515.     "Add records",
  1516.     "Utilities",
  1517.     ma,
  1518.     hil,
  1519.     "Exit to DOS"
  1520. };
  1521.  
  1522. int menu( void )
  1523. {
  1524.     union REGS x;
  1525.  
  1526.     if ( FRSREC( ixnam, vrec ) == 0 )  /* get first record, if possible */
  1527.         ;
  1528.  
  1529.     while (1)
  1530.     {
  1531.         normal_video();
  1532.         fullscreen();
  1533.         put_screen();
  1534.  
  1535.         /* re-read current record, if possible */
  1536.         if ( REDVREC( datno, vrec, BUFSIZE ) == 0 ) 
  1537.         {
  1538.             load_form();
  1539.             show_form();
  1540.         }
  1541.  
  1542.         switch ( select( MLOC, 1, &amenu[0], (sizeof(amenu)/sizeof(char *))))
  1543.         {
  1544.         case 0:
  1545.             scan_records();
  1546.             break;
  1547.  
  1548.         case 1:
  1549.             new_record( MANY );  /* add a batch of records */
  1550.             break;
  1551.  
  1552.         case 2:
  1553.             utilities();
  1554.             break;
  1555.  
  1556.         case 3:
  1557.             if ( video.mode == 3 || video.mode == 2 )
  1558.             {
  1559.                 video.SnowFlag ^= 1;
  1560.                 amenu[3] = video.SnowFlag ? qp : pq;
  1561.                 if ( ask( "Save value?" ) )
  1562.                     save_color();
  1563.             }
  1564.             else
  1565.                 boxmsg( "Monochrome adapters don't have snow!" );
  1566.             break;
  1567.  
  1568.         case 4:
  1569.             PopScreen( burlap_screen ); /* fresh canvas */
  1570.             clairol();
  1571.             MSJ_MovScrBuf( burlap_screen, 0, 0, 2000, &video );
  1572.             if ( ask( "Save values?" ) )
  1573.                 save_color();
  1574.             break;
  1575.  
  1576.         default:
  1577.             if ( ask( "^1Exit to DOS?^0" ) )
  1578.                 return;
  1579.             break;
  1580.         }
  1581.     }
  1582. }
  1583.  
  1584.  
  1585. main( int argc, char *argv[] )
  1586. {
  1587.     char **p;
  1588.     FILE *fp;
  1589.     int i;
  1590.  
  1591.     static char *pinfo[] = {
  1592.     "12 3 4 1",
  1593.     "",
  1594.     " 0   burlap.dt      0   4096  4  3 lname rem",
  1595.     "  1  burlap.ix     24  8 1  2  4096  0 0   0  2 name",
  1596.     "     0  15 5",
  1597.     "     1   5 5",
  1598.     "  2                24  8 1             0   0  3 zip",
  1599.     "     7  10 5",
  1600.     "     0   5 5",
  1601.     "     1   5 5",
  1602.     "  3                24  8 1             0   0  3 conam",
  1603.     "     2  10 5",
  1604.     "     0   5 5",
  1605.     "     1   5 5",
  1606.     "",
  1607.     "",
  1608.     "Note:  BURLAP.EXE always starts up using the parameter file BURLAP.P,",
  1609.     "       located in the currently active subdirectory.  BURLAP.P directs",
  1610.     "       c-tree(TM) ISAM file manager to the appropriate BURLAP files as",
  1611.     "       given above.  You may give a complete path to another directory.",
  1612.     "",
  1613.     "       ********************    C A U T I O N    ***********************",
  1614.     "       *  Do Not Change Any Part Of This File Except For Path Names!  *",
  1615.     "       ********************    C A U T I O N    ***********************",
  1616.     NULL
  1617.     };
  1618.  
  1619.     vid_init(0);
  1620.     video.SnowFlag = 0;  /* assume if mode 3 or 2, video card is NOT a CGA */
  1621.     get_color();         /* is there a user configuration file? */
  1622.     if (video.mode == 3 || video.mode == 2 )
  1623.     {
  1624.         amenu[3] = video.SnowFlag ? qp : pq;
  1625.         amenu[4] = hue;
  1626.     }
  1627.     setsynch(0);
  1628.  
  1629.     /* any file names on the command line? */
  1630.  
  1631.     parameter_file_name = PARMFILE;
  1632.     screen_file_name    = SCRNFILE;
  1633.     macro_file_name     = (char *) NULL;
  1634.  
  1635.     for ( i = 1; i < argc; i++ )
  1636.     {
  1637.         strlwr( argv[i] );
  1638.         if ( strstr( argv[i], ".p" ) != NULL )
  1639.             parameter_file_name = argv[i];
  1640.         if ( strstr( argv[i], ".s" ) != NULL )
  1641.             screen_file_name = argv[i];
  1642.         if ( strstr( argv[i], ".m" ) != NULL )
  1643.         {
  1644.             macro_file_name = argv[i];
  1645.             load_default_macro();
  1646.         }
  1647.     }
  1648.  
  1649.     /* set printer to binary mode, i.e., use explicit "\r\n" newlines */
  1650.  
  1651.     setmode( fileno(stdprn),O_BINARY );
  1652.  
  1653.     /* blank startup?  create the parameter file, if needed */
  1654.  
  1655.     if ( access( parameter_file_name, 0 ) == 0 )  
  1656.         ; /* do nothing, parameter file exists */
  1657.     else
  1658.     {
  1659.         if ( access( ISAMFILE, 0 ) == 0 || 
  1660.              access( INDXFILE, 0 ) == 0  
  1661.            )
  1662.         {
  1663.             bomb("Data files exist, so must not create parameter file!");
  1664.         }
  1665.  
  1666.         fp = fopen( parameter_file_name, "wt" );
  1667.         if ( fp == NULL || ferror(fp) )
  1668.             bomb("can't create parameter file: %s", strerror(errno));
  1669.         for ( p = pinfo; *p != NULL; p++ )
  1670.         {
  1671.             fprintf( fp, "%s\n", *p );
  1672.         }
  1673.         fclose (fp);
  1674.     }
  1675.  
  1676.     set_crash_function( CLISAM );  /* tell bomb0 to close ISAM files */
  1677.  
  1678.     AllocateFields( burlap, ALLOCATE );
  1679.  
  1680.     reopen_ISAM_files();  /* creates empty ISAM files, if needed */
  1681.  
  1682.     signal(SIGINT,osiris);
  1683.     if (setjmp(isis))  /* if Ctrl-C, ISAM files must be closed on exit */
  1684.         ;
  1685.     else
  1686.         menu();
  1687.  
  1688.     nboxmsg("Closing ISAM files");
  1689.     close_ISAM_files();
  1690.  
  1691.     ReleaseFields( burlap, ALLOCATE );
  1692.     exit_fafnir();
  1693.  
  1694.     vid_exit();
  1695.     exit (0);
  1696. }
  1697.  
  1698.